// 实现这个项目的构建任务
const {src, dest, series, parallel} = require('gulp')
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins() // 调用加载插件方法
// const plugins.watch = require('gulp-watch') // gulp版本为4.0.2， 内置的watch函数只监听一次就停止，单独引入插件gulp-watch解决
const del = require('del')
const browserSync = require('browser-sync')
const { stream } = require('browser-sync')
const bs = browserSync.create() // 创建一个服务器
const cwd = process.cwd()
// 填充数据
let config = {
    data: {
        menus: [{
            name: '首页',
            link: 'index.html'
        }, {
            name: '关于我们',
            link: 'about.html'
        }],
        pkg: require('./package.json'),
        date: new Date()
    },
    build: {
        src: 'src',
        public: 'public',
        dist: 'dist',
        temp: 'temp',
        paths: {
            style: 'assets/style/**',
            script: 'assets/scripts/*.js',
            images: 'assets/images/**',
            pages: '**/*.html',
            fonts: 'assets/fonts/**'
        }
    }
}
// 合并跟路径下page配置文件
try {
  const loadConfig = require(`${cwd}/pages.config.js`)
  config = Object.assign({}, config, loadConfig)
} catch(e) {}
// 定义路径
const srcDir = config.build.src
const public = config.build.public
const dist = config.build.dist
const temp = config.build.temp
const stylePath = config.build.paths.style
const jsPath = config.build.paths.script
const imgPath = config.build.paths.images
const pagePath = config.build.paths.pages
const fontPath = config.build.paths.fonts
// 清空文件
const clean = () => {
    return del([dist, temp])
}
// 处理css文件
const style = () => {
    return src(stylePath, {base: srcDir, cwd: srcDir})
           .pipe(plugins.sass({outputStyle: "expanded"}))
           .pipe(dest(temp))
}

// 处理js
const script = () => {
    return src(jsPath, {base: srcDir, cwd: srcDir})
           .pipe(plugins.babel({presets: ['@babel/preset-env']})) // presets必须为一个数组
           .pipe(dest(temp))
}

// 处理html
const pages = () => {
    return src(pagePath, {base: srcDir, cwd: srcDir})
           .pipe(plugins.swig({data: config.data, defaults: {cache: false}})) // defaults: {cache: false}是为了不适用swig的缓存，否则会出现修改html文件页面刷新但是内容不更新问题
           .pipe(dest(temp))
}

// 处理image
const image = () => {
    return src(imgPath, {base: srcDir, cwd: srcDir})
           .pipe(plugins.imagemin())
           .pipe(dest(dist))
}

// 处理fonts文件
const fonts = () => {
    return src(fontPath, {base: srcDir, cwd: srcDir})
           .pipe(plugins.imagemin())
           .pipe(dest(dist))
}

// 处理其他文件
const extra = () => {
    return src('**', {base: public, cwd: public})
           .pipe(dest(dist))
}

// 搭建开发服务器
const serve = () => {
    // 监听各文件变化并执行相应任务
    plugins.watch([imgPath, fontPath], {cwd: srcDir}, bs.reload)
    plugins.watch(['**'], {cwd: public}, bs.reload)
    plugins.watch(pagePath, {cwd: srcDir}, pages)
    plugins.watch([jsPath], {cwd: srcDir}, script)
    plugins.watch([stylePath], {cwd: srcDir}, style)
    bs.init({
        files: temp, // 监听目录下文件变化
        notify: false,
        server: {
            baseDir: [temp, srcDir, public], // 网站根目录
            routes: {
                '/node_modules': 'node_modules' // 为/node_modules开头的资源文件指定router
            }
        }
    })
}

// 上线前处理资源文件
const useref = () => {
    return src(pagePath, {base: temp, cwd: temp})
           .pipe(plugins.useref({searchPath: [temp, '.']})) // 合并该目录下资源文件
           .pipe(plugins.if(/\.js$/, plugins.uglify())) // plugins.if判断不同文件执行不同压缩操作
           .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
           .pipe(plugins.if(/\.html$/, plugins.htmlmin({minifyCSS: true, minifyJS: true, removeComments: true, collapseWhitespace: true})))
           .pipe(dest(dist))

}

const compile = parallel(style, script, pages)
const dev = series(clean, compile, serve) // 组合开发任务
const build = series(
                clean,
                parallel(
                    series(compile, useref), 
                    fonts, image, extra
                )
            ) // 组合上线任务
                
// 导出任务
module.exports = {
    clean,
    dev,
    build
}